package com.guocheng.utils;

import com.guocheng.common.annotation.TerminalRequest;
import com.guocheng.common.annotation.TerminalResponse;
import com.guocheng.modules.emp.model.po.Emp;
import org.springframework.util.LinkedMultiValueMap;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

public class TerminalsFiledUtils {

    /**
     * map方式赋值
     *
     * @param map   获取来的map数据
     * @param c
     * @param <T>
     * @return
     */
    public static <T> T to(Map<String, Object> map, Class<T> c) {
        T t = null;
        try {
            t = c.newInstance();
        } catch (Exception e) {
            throw new RuntimeException("创建类失败，需要无参构造方法！");
        }
        Class<?> t1 = t.getClass();

        //给字段赋值
        Field[] fields = t1.getDeclaredFields();
        for (Field field : fields) {
            try {
                field.setAccessible(true);      //暴力访问
                //转换注解
                TerminalResponse annotation = field.getAnnotation(TerminalResponse.class);

                //是否存在转换注解
                if (annotation != null) {
                    String[] names = annotation.value();
                    String name = names[0];         //获取字段名称
                    Object o = null;                //字段值

                    Class<?> type = annotation.type();      //获取转换类型
                    String methods = annotation.methods();  //获取转换方法

                    //判断是否存在自定义转换方法
                    if(!methods.equals("")){
                        //获取工具类
                        Class<?> utils = annotation.utils();
                        //获取方法参数
                        Class<?>[] arg = annotation.arg();
                        //反射方法
                        Method method = utils.getMethod(methods,arg);
                        //获取所有的值
                        Object[] objects = new Object[names.length];
                        for (int i = 0; i < names.length; i++) {
                            objects[i]=map.get(names[i]);
                        }
                        //执行方法
                        o = method.invoke(utils, objects);
                    }else
                        //先判断是否存在指定类型
                        if (type != void.class) {
                            o = map.get(name); //获取字段值
                            //如果为list包含类,则创建每一个对象
                            if(o instanceof List){
                                List list = (List)o;
                                //创建一个新的list
                                List list1 = new ArrayList<>();
                                //循环每一个list并创建对象
                                for (Object o1 : list) {
                                    //如果循环的是个map对象
                                    if(o1 instanceof Map) {
                                        list1.add(to((Map) o1, type));
                                    }
                                    //否则循环的是个其他对象
                                    else{
                                        //如果不是String类型，则转换的类需要提供携带String的构造方法
                                        Constructor<?> constructor = type.getConstructor(String.class);
                                        list1.add(constructor.newInstance(o));
                                    }
                                }
                                o=list1;
                            }else
                                //如果单包含类，则接收的值应为map
                                if(o instanceof Map){
                                    Map map1 = (Map)o;
                                    o = to(map1, type);
                                }else{
                                    //如果不是String类型，则转换的类需要提供携带String的构造方法
                                    Constructor<?> constructor = type.getConstructor(String.class);
                                    o = constructor.newInstance(o);
                                }
                        }else{
                            o=map.get(name);
                        }
                    //赋值
                    field.set(t, o);
                }
            } catch (Exception e) {
                throw new RuntimeException("字段赋值失败！", e);
            }
        }
        return t;
    }


    /**
     * list赋值
     * @param list
     * @param c
     * @param <T>
     * @return
     */
    public static <T> List<T> to(List<Map<String,Object>> list,Class<T> c){
        return list.stream().map(t -> to(t, c)).collect(Collectors.toList());
    }

    /**
     * 将实体类转换为body数据
     * @param o
     * @return
     */
    public static LinkedMultiValueMap<String, Object> body(Object o){
        LinkedMultiValueMap<String, Object> map = new LinkedMultiValueMap<>();
        //获得类的的属性名 数组
        Field[] fields=o.getClass().getDeclaredFields();
        String name=null;
        try {

            for (Field field : fields) {
                field.setAccessible(true);
                //转换注解
                TerminalRequest annotation = field.getAnnotation(TerminalRequest.class);
                if(annotation!=null){
                    name = annotation.value();      //获取字段名称
                    Object o1 = field.get(o);;      //获取当前字段值
                    if(o1==null)continue;

                    Class<?> type = annotation.type();      //获取转换类型
                    String methods = annotation.methods();  //获取转换方法

                    if(!methods.equals("")){
                        //获取工具类
                        Class<?> utils = annotation.utils();
                        //获取方法参数
                        Class<?> arg = annotation.arg();
                        //反射方法
                        Method method = utils.getMethod(methods,o1.getClass());
                        //执行方法
                        o1 = method.invoke(utils, o1);
                    }else
                    //判断是否存在指定类型
                    if (type != void.class) {
                        //如果不是String类型，则转换的类需要提供携带String的构造方法
                        Constructor<?> constructor = type.getConstructor(String.class);
                        o1 = constructor.newInstance(o1.toString());
                    }
                    map.add(name,o1);
                }
            }
        }catch (Exception e){
            throw new RuntimeException("'"+name+"'字段赋值失败！",e);
        }
        return map;
    }
}
